package com.ocean.admin.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ocean.admin.entity.SysDictData;
import com.ocean.admin.extension.ConstantsCacheExtension;
import com.ocean.admin.extension.security.core.SysUserDetails;
import com.ocean.admin.extension.security.filter.WebFilterExtend;
import com.ocean.admin.mapper.SysDictDataMapper;
import com.ocean.admin.model.dto.dicdata.SysDictDataQueryDTO;
import com.ocean.admin.model.dto.dicdata.SysDictDataSaveDTO;
import com.ocean.admin.model.dto.dicdata.SysDictDataUpdateDTO;
import com.ocean.admin.model.vo.dicdata.SysDictDataVo;
import com.ocean.admin.service.ISysDictDataService;
import com.ocean.cache.redis.IRedisCache;
import com.ocean.core.exception.verify.ApplicationException;
import com.ocean.core.util.constants.ConstantsAttribute;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;

/**
 * <p>
 * 字典数据表 服务实现类
 * </p>
 *
 * @author zhang
 * @since 2022-08-16
 */
@Service
public class SysDictDataServiceImpl extends ServiceImpl<SysDictDataMapper, SysDictData> implements ISysDictDataService {

    @Autowired
    private IRedisCache iRedisCache;

    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    /**
     * 分页查询字典数据
     *
     * @param queryDTO 查询条件
     * @return 结果
     */
    @Override
    public IPage<SysDictDataVo> pageList(SysDictDataQueryDTO queryDTO) {
        Page<SysDictDataVo> page = new Page<>(queryDTO.getPage(), queryDTO.getPageSize());
        IPage<SysDictDataVo> pageList = baseMapper.pageList(page, queryDTO);
        pageList.getRecords().forEach(res -> {
            res.setStatusName(res.getStatus() == 1 ? "停用" : "正常");
        });
        return pageList;
    }

    /**
     * 新增字典类型
     *
     * @param saveDTO 字典信息
     * @return 结果
     */
    @Override
    public String saveDicData(SysDictDataSaveDTO saveDTO) {
        this.checkSaveDicData(saveDTO);
        SysDictData dictData = new SysDictData();
        BeanUtils.copyProperties(saveDTO, dictData);
        SysUserDetails current = WebFilterExtend.current();
        dictData.setCreateUserId(current.getUserId());
        dictData.setCreateUserName(current.getNickName());
        dictData.setUpdateUserId(current.getUserId());
        dictData.setUpdateUserName(current.getNickName());
        this.save(dictData);
        iRedisCache.del(ConstantsCacheExtension.getInstance().getDicCache() + saveDTO.getDictType());
        return ConstantsAttribute.INSERT_SUCCESS;
    }

    /**
     * 修改字典类型
     *
     * @param updateDTO 字典信息
     * @return 结果
     */
    @Override
    public String updateDicData(SysDictDataUpdateDTO updateDTO) {
        this.checkUpdateDicData(updateDTO);
        SysDictData dictData = new SysDictData();
        BeanUtils.copyProperties(updateDTO, dictData);
        SysUserDetails current = WebFilterExtend.current();
        dictData.setUpdateUserId(current.getUserId());
        dictData.setUpdateUserName(current.getNickName());
        this.updateById(dictData);
        iRedisCache.del(ConstantsCacheExtension.getInstance().getDicCache() + updateDTO.getDictType());
        return ConstantsAttribute.UPDATE_SUCCESS;
    }

    /**
     * 删除字典类型
     *
     * @param dataId 字典编码
     * @return 结果
     */
    @Override
    public String removeDicData(Long[] dataId) {
        List<Long> dataIdList = Arrays.asList(dataId);
        this.removeByIds(dataIdList);
        List<SysDictData> sysDictData = baseMapper.selectBatchIds(dataIdList);
        for (SysDictData data : sysDictData) {
            iRedisCache.del(ConstantsCacheExtension.getInstance().getDicCache() + data.getDictType());
        }
        return ConstantsAttribute.REMOVE_SUCCESS;
    }

    /**
     * 根据字典类型获取字典数据列表
     *
     * @param dicType 字典类型
     * @return 结果
     */
    @Override
    public List<SysDictData> datalist(String dicType) {
        return baseMapper.selectList(Wrappers.<SysDictData>lambdaQuery().eq(SysDictData::getDictType, dicType)
                .eq(SysDictData::getStatus, 0).orderByAsc(SysDictData::getDictSort));
    }

    /**
     * 根据字典类型查询字典数据
     *
     * @param dicType 字典类型
     * @return 结果
     */
    @Override
    public Map<Integer, String> selectMapDicData(String dicType) {
        Map<Integer, String> cachedData = this.read(dicType);
        if (cachedData == null || cachedData.isEmpty()) {
            return this.write(dicType);
        }
        return cachedData;
    }

    private Map<Integer, String> read(String dicType) {
        lock.readLock().lock();
        try {
            return readFromCache(dicType);
        } finally {
            lock.readLock().unlock();
        }
    }

    public Map<Integer, String> write(String dicType) {
        lock.writeLock().lock();
        try {
            List<SysDictData> dataList = baseMapper.selectList(Wrappers.<SysDictData>lambdaQuery().eq(SysDictData::getDictType, dicType));
            if (!dataList.isEmpty()) {
                writeToCache(dicType, dataList);
            }
            return convertToMap(dataList);
        } finally {
            lock.writeLock().unlock();
        }
    }

    private Map<Integer, String> convertToMap(List<SysDictData> dataList) {
        return dataList.stream().collect(Collectors.toMap(
                SysDictData::getDictValue,
                SysDictData::getDictLabel,
                (key1, key2) -> key1
        ));
    }

    private Map<Integer, String> readFromCache(String dicType) {
        Object result = iRedisCache.get(ConstantsCacheExtension.getInstance().getDicCache() + dicType);
        if (result instanceof List) {
            return convertToMap((List<SysDictData>) result);
        }
        return null;
    }

    private void writeToCache(String dicType, List<SysDictData> dataList) {
        iRedisCache.set(ConstantsCacheExtension.getInstance().getDicCache() + dicType, dataList);
    }

    private void checkSaveDicData(SysDictDataSaveDTO saveDTO) {
        Long valueCount = baseMapper.selectCount(Wrappers.<SysDictData>lambdaQuery().eq(SysDictData::getDictType,
                        saveDTO.getDictType())
                .eq(SysDictData::getDictValue, saveDTO.getDictValue()));
        if (valueCount > 0) {
            throw new ApplicationException("数据键值已存在，请更换");
        }
    }

    private void checkUpdateDicData(SysDictDataUpdateDTO updateDTO) {
        SysDictData dictData = baseMapper.selectOne(Wrappers.<SysDictData>lambdaQuery().eq(SysDictData::getDictType,
                updateDTO.getDictType()).eq(SysDictData::getDictValue, updateDTO.getDictValue()));
        if (dictData != null && !Objects.equals(updateDTO.getDataId(), dictData.getDataId())) {
            throw new ApplicationException("数据键值已存在，请更换");
        }
    }
}
